

import axios, { AxiosStatic } from 'axios';
import { formItemType, FormItemType } from '../form-helper';

export interface BaseVm {
    id: number;
}

export class BaseModel {
    @formItemType("ID", FormItemType.ID)
    id: number = 0;
}

export interface PagerInterface<T extends BaseModel> { 
    fetch(): Promise<this>;
    hasNextPage(): boolean;
    hasPrevPage(): boolean;
    nextPage(): Promise<this>;
    prevPage(): Promise<this>;
    getTotalPage(): number;
    items: T[];
}

class Pager<T extends BaseModel, U extends BaseVm> implements PagerInterface<T>{ 
    public count: number = 0;
    public items: T[] = [];
    constructor(public service: AbstractBaseService<T, U>, public options?: any, public page: number = 0, public pagesize: number = 20) { 
        if (!options) { 
            this.options = {};
        }
    }
    async fetch(): Promise<this>{ 
        let ret = await this.service._find(this.page, this.pagesize, this.options, );
        let count: number = ret.count;
        let items: U[] = ret.items;
        this.count = count;
        this.items = items.map((vm) => {
            return this.service.fromVmToModel(vm);
        });
        return this;
    }
    hasNextPage() {
        return this.page+1 < this.getTotalPage();
    }
    async nextPage(): Promise<this>{ 
        if (!this.hasNextPage()) { 
            throw new Error("没有下一页了");
        }
        this.page++;
        return this.fetch();
    }
    hasPrevPage() { 
        return this.page > 0;
    }
    async prevPage(): Promise<this> { 
        if (!this.hasPrevPage()) { 
            throw new Error("没有上一页了");
        }
        this.page--;
        return this.fetch();
    }
    getTotalPage() { 
        return Math.ceil(this.count / this.pagesize);
    }
}

export abstract class AbstractBaseService<T extends BaseModel, U extends BaseVm> { 
    constructor(public resource: string, public host?: string) { 
    }
    public request: AxiosStatic = axios;
    async get(id: number): Promise<T> { 
        const url = this.getUrl(id);
        let data: U = this.handleResponse(await this.request.get(url));
        return this.fromVmToModel(data);
    }
    async add(obj: T): Promise<T> { 
        const url = this.getUrl("");
        const vm = this.fromModelToVm(obj);
        let data: U = this.handleResponse(await this.request.post(url, vm));
        return this.fromVmToModel(data);
    }
    async save(obj: T): Promise<T> { 
        const url = this.getUrl(obj.id);
        const vm = this.fromModelToVm(obj);
        let data: U;
        if (obj.id) {
            data = this.handleResponse(await this.request.put(url, vm));
        } else { 
            data = this.handleResponse(await this.request.post(url, vm));
        }
        return this.fromVmToModel(data);
    }

    async _find(page: number, pagesize: number, params?: any): Promise<{items: U[], count: number}>{ 
        if (!params) {
            params = {};
        }
        params.page = page;
        params.pagesize = pagesize;
        const url = this.getUrl("");
        let data: any = this.handleResponse(await this.request.get(url, { params: params}));
        let { items, count } = data;
        return { items, count };
    }

    async find(page: number=0, pagesize: number=20, options?: any): Promise<Pager<T, U>> { 
        const pager = new Pager<T, U>(this, options, page, pagesize);
        return pager.fetch();
    }

    getUrl(id?: number | string) { 
        if (!this.host) { 
            this.host = '';
        }
        return this.getHost() + '/' + this.resource + '/' + id;
    }
    handleResponse(resp: any): any{ 
        return resp.data;
    }
    private getHost() { 
        if (this.host) { 
            return this.host;
        }
        const localHost = localStorage.getItem("_pig_cms_api_host");
        if (localHost) { 
            return localHost;
        }
        return 'http://localhost:4000';
    }
    abstract fromVmToModel(vm: U): T;
    abstract fromModelToVm(model: T): U;
} 